package slog

import (
	"fmt"
	"gitee.com/clannad_sk/otool/clannad/os/glog"
	"gitee.com/clannad_sk/otool/clannad/os/gtime"
	"gitee.com/clannad_sk/otool/clannad/util/gconv"
	"gitee.com/clannad_sk/otool/common/goid"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var (
	logger = glog.New()
)

func init() {
	levelPrefixes := make(map[int]string)
	levelPrefixes[64] = "WARN"
	levelPrefixes[128] = "ERROR"
	levelPrefixes[256] = "CRIT"
	levelPrefixes[512] = "PANI"
	levelPrefixes[1024] = "FATA"
	levelPrefixes[8] = "DEBUG"
	levelPrefixes[16] = "INFO"
	levelPrefixes[32] = "NOTI"
	logConfig := glog.Config{
		HeaderPrint:          true,
		LevelPrefixes:        levelPrefixes,
		Level:                504,
		StSkip:               0,
		StStatus:             1,
		StFilter:             "",
		StdoutPrint:          true,
		RotateSize:           0,
		RotateExpire:         0,
		RotateBackupLimit:    0,
		RotateBackupExpire:   0,
		RotateBackupCompress: 0,
		RotateCheckInterval:  gtime.H,
	}
	err := logger.SetConfig(logConfig)
	if err != nil {
		fmt.Println("ERROR! init logger err!", err)
	}
}

func GetLogger() *glog.Logger {
	return logger
}

func SetDebug(canDebug bool) {
	logger.SetDebug(canDebug)
}

// [等级] [线程] [位置] - body
func Debug(v ...interface{}) {
	logger.Debug(formatLog(v)...)
	//logger.Debug(stackDump())
}

// Printf prints <v> with format <format> using fmt.Sprintf.
// The parameter <v> can be multiple variables.
func Printf(format string, v ...interface{}) {
	logger.Printf(format, v...)
}

// See Print.
func Println(v ...interface{}) {
	logger.Println(v...)
}

// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
func Fatal(v ...interface{}) {
	logger.Fatal(v...)
}

// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
func Fatalf(format string, v ...interface{}) {
	logger.Fatalf(format, v...)
}

// Panic prints the logging content with [PANI] header and newline, then panics.
func Panic(v ...interface{}) {
	logger.Panic(v...)
}

// Panicf prints the logging content with [PANI] header, custom format and newline, then panics.
func Panicf(format string, v ...interface{}) {
	logger.Panicf(format, v...)
}

// Info prints the logging content with [INFO] header and newline.
func Info(v ...interface{}) {
	logger.Info(formatLog(v)...)
}

// Infof prints the logging content with [INFO] header, custom format and newline.
func Infof(format string, v ...interface{}) {
	logger.Infof(format, v...)
}

// Debugf prints the logging content with [DEBU] header, custom format and newline.
func Debugf(format string, v ...interface{}) {
	logger.Debugf(format, v...)
}

// Notice prints the logging content with [NOTI] header and newline.
// It also prints caller stack info if stack feature is enabled.
func Notice(v ...interface{}) {
	logger.Notice(v...)
}

// Noticef prints the logging content with [NOTI] header, custom format and newline.
// It also prints caller stack info if stack feature is enabled.
func Noticef(format string, v ...interface{}) {
	logger.Noticef(format, v...)
}

// Warning prints the logging content with [WARN] header and newline.
// It also prints caller stack info if stack feature is enabled.
func Warning(v ...interface{}) {
	logger.Warning(formatLog(v)...)
}

// Warningf prints the logging content with [WARN] header, custom format and newline.
// It also prints caller stack info if stack feature is enabled.
func Warningf(format string, v ...interface{}) {
	logger.Warningf(format, v...)
}

// Error prints the logging content with [ERRO] header and newline.
// It also prints caller stack info if stack feature is enabled.
func Error(v ...interface{}) {
	logger.Error(formatLog(v)...)
}

// Errorf prints the logging content with [ERRO] header, custom format and newline.
// It also prints caller stack info if stack feature is enabled.
func Errorf(format string, v ...interface{}) {
	logger.Errorf(format, v...)
}

// Critical prints the logging content with [CRIT] header and newline.
// It also prints caller stack info if stack feature is enabled.
func Critical(v ...interface{}) {
	logger.Critical(v...)
}

// Criticalf prints the logging content with [CRIT] header, custom format and newline.
// It also prints caller stack info if stack feature is enabled.
func Criticalf(format string, v ...interface{}) {
	logger.Criticalf(format, v...)
}

func SetPath(path string) error {
	return logger.SetPath(path)
}

func formatLog(v ...interface{}) []interface{} {
	all := make([]interface{}, 0)
	all = append(all, "[Cur-GoID-"+gconv.String(goid.GetGid())+"]")
	if _, file, line, ok := runtime.Caller(2); ok {
		if strings.Contains(file, "/Users/wjl/Desktop/clannad_work/go_proj/") {
			file = strings.ReplaceAll(file, "/Users/wjl/Desktop/clannad_work/go_proj/", "")
		}
		all = append(all, fmt.Sprintf("[file: %s, line: %d]", file, line))
	}
	curTime := time.Now()
	all = append(all, fmt.Sprintf("- %s ", curTime.Format("2006-01-02 15:04:05")))
	for _, args := range v {
		for _, arg := range args.([]interface{}) {
			all = append(all, arg)
		}
	}

	return all
}

func stackDump() string {
	pcs := make([]uintptr, 16)
	n := runtime.Callers(0, pcs)

	frames := runtime.CallersFrames(pcs[:n])

	var buffer strings.Builder
	for {
		frame, more := frames.Next()

		buffer.WriteString(frame.Function)
		buffer.WriteByte('\n')
		buffer.WriteByte('\t')
		buffer.WriteString(frame.File)
		buffer.WriteByte(':')
		buffer.WriteString(strconv.Itoa(frame.Line))
		buffer.WriteByte('\n')

		if !more {
			break
		}
	}

	return buffer.String()
}
